package cn.linjianhui.api.client.invoker.impl;

import cn.linjianhui.api.client.exception.RpcClientException;
import cn.linjianhui.api.client.DataFormat;
import cn.linjianhui.api.client.invoker.*;
import cn.linjianhui.api.client.util.HttpUtils;
import org.apache.http.HttpResponse;
import org.springframework.util.ObjectUtils;

import java.util.List;

public class HttpInvoker extends RPCInvoker {

    public HttpInvoker(String serviceUri, String baseAddress, String[] parameters, Class<?> returnType,
                       Class<?> genericType, ClientAuthenticator authenticator, Serializer serializer, DataFormat dataFormat) {
        super(serviceUri, baseAddress, parameters, returnType, genericType, authenticator, serializer, dataFormat);
    }

    @Override
    public Object doMethodInvoker(Object[] methodArgs) throws Exception {

        HttpClient httpClient = new HttpClientImpl(this.serializer, this.dataFormat);

        if(ObjectUtils.isEmpty(authenticator)
                || !(authenticator instanceof HttpClientTokenAuthenticator)) {
            throw new RpcClientException("ClientAuthenticator cannot be null and must be HttpClientTokenAuthenticator");
        }

        HttpClientTokenAuthenticator httpClientTokenAuthenticator = (HttpClientTokenAuthenticator)authenticator;
        HttpRequestParam param = httpClientTokenAuthenticator.getRequestParam();
        HttpResponse response;
        if(parameters.length > 0) {
            for (int index = 0;  index < this.parameters.length; index++) {
                param.getBody().put(parameters[index], methodArgs[index]);
            }
            response = httpClient.post(httpClientTokenAuthenticator);
        }else {
            response = httpClient.get(httpClientTokenAuthenticator);
        }

        int statusCode = response.getStatusLine().getStatusCode();
        String content = HttpUtils.getUTF8Content(response);
        if(statusCode != 200) {
            throw new RpcClientException(content);
        }else {
            httpClientTokenAuthenticator.refreshToken(response);

            if(returnType == null || returnType.getName().equals(void.class.getName())) {
                return null;
            }

            if(returnType.getName().equals(List.class.getName())) {
                if(this.genericType == null) {
                    throw new RpcClientException("generic return type cannot be null");
                }
                return this.serializer.deserializeArray(content, this.genericType);
            }else {
                return this.serializer.deserialize(content, this.returnType);
            }
        }
    }
}
